#pragma once
#include "vec3f.h"
#include <vector>
#include <set>
#include <Windows.h>	
using namespace std;


//Stores information regarding a ball
struct Ball {
	Vec3f v; //Velocity
	Vec3f pos; //Position
	float r; //Radius
	Vec3f color;
};

//Stores a pair of balls
struct BallPair {
	Ball* ball1;
	Ball* ball2;
};

enum Wall {WALL_LEFT, WALL_RIGHT, WALL_FAR, WALL_NEAR, WALL_TOP, WALL_BOTTOM};

//OCTREE globals.
const int MAX_OCTREE_DEPTH = 6;
const int MIN_BALLS_PER_OCTREE = 3;
const int MAX_BALLS_PER_OCTREE = 6;

//Stores a ball and a wall
struct BallWallPair {
	Ball* ball;
	Wall wall;
};

class Octree {
private:
	Vec3f corner1; //(minX, minY, minZ)
	Vec3f corner2; //(maxX, maxY, maxZ)
	Vec3f center;//((minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2)
	

	CRITICAL_SECTION CriticalSection;
	/* The children of this, if this has any.  children[0][*][*] are the
		* children with x coordinates ranging from minX to centerX.
		* children[1][*][*] are the children with x coordinates ranging from
		* centerX to maxX.  Similarly for the other two dimensions of the
		* children array.
		*/
	Octree *children[2][2][2];
	//Whether this has children
	bool hasChildren;
	//The balls in this, if this doesn't have any children
	set<Ball*> balls;
	//The depth of this in the tree
	int depth;
	//The number of balls in this, including those stored in its children
	int numBalls;
		
	//Adds a ball to or removes one from the children of this
	void fileBall(Ball* ball, Vec3f pos, bool addBall);//Figure out in which child(ren) the ball belongs
		
	//Creates children of this, and moves the balls in this to the children
	void haveChildren();

	//Adds all balls in this or one of its descendants to the specified set
	void collectBalls(set<Ball*> &bs);

	//Destroys the children of this, and moves all balls in its descendants
	//to the "balls" set
	void destroyChildren();
		
	//Removes the specified ball at the indicated position
	void remove(Ball* ball, Vec3f pos);
		
	/* Helper fuction for potentialBallWallCollisions(vector).  Adds
		* potential ball-wall collisions to cs, where w is the type of wall,
		* coord is the relevant coordinate of the wall ('x', 'y', or 'z'), and
		* dir is 0 if the wall is in the negative direction and 1 if it is in
		* the positive direction.  Assumes that this is in the extreme
		* direction of the coordinate, e.g. if w is WALL_TOP, the function
		* assumes that this is in the far upward direction.
		*/
	void potentialBallWallCollisions(vector<BallWallPair> &cs,
										Wall w, char coord, int dir);

public:
	//Constructs a new Octree.  c1 is (minX, minY, minZ), c2 is (maxX, maxY,
	//maxZ), and d is the depth, which starts at 1.
	Octree(Vec3f c1, Vec3f c2, int d);
		
	//Destructor
	~Octree();
		
	//Adds a ball to this
	void add(Ball* ball);
		
	//Removes a ball from this
	void remove(Ball* ball);
		
	//Changes the position of a ball in this from oldPos to ball->pos
	void ballMoved(Ball* ball, Vec3f oldPos);
		
	//Adds potential ball-ball collisions to the specified set
	void potentialBallBallCollisions(vector<BallPair> &collisions);
		
	//Adds potential ball-wall collisions to the specified set
	void potentialBallWallCollisions(vector<BallWallPair> &collisions);
};


